#pragma once

// 为使用 asio 线程池
// #include <websocketpp/config/asio.hpp> 
// #include <boost/asio.hpp>


#include <iostream>
#include <thread>
#include <sstream>

#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
#include <websocketpp/frame.hpp>
using websocketpp::lib::bind;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::placeholders::_3;
typedef websocketpp::server<websocketpp::config::asio> server;
typedef websocketpp::connection_hdl connection_hdl;
typedef server::message_ptr message_ptr;

#include "op_distributor.hpp"
#include "SendTaskQueue.hpp"
#include "UserManagement.hpp"
#include "utility.hpp"


class websocketpp_server
{
private:
    server server_;
    int port_;
    static op_distributor op_dis_;
    static std::thread* thread_sever_;
    
    // std::unique_ptr<websocketpp::lib::thread> io_service_thread_;
    // std::shared_ptr<boost::asio::thread_pool> asio_thread_pool_;

public:
    websocketpp_server(/* args */);
    ~websocketpp_server();
    void set_port(int port) { port_ = port; }
    void run() 
    {
        
        server_.init_asio();
        // 多线程
        // asio_thread_pool_ = std::make_shared<boost::asio::thread_pool>(10);
        // io_service_thread_.reset(new websocketpp::lib::thread(&server::run, &server_));

        server_.listen(port_);
        server_.start_accept();
        
        
        // 把服务器放到别的线程里去跑
        // websocketpp::lib::thread* asio_thread = new websocketpp::lib::thread(&server::run, &server_);

        // 多线程
        typedef websocketpp::lib::shared_ptr<websocketpp::lib::thread> thread_ptr;
        std::vector<thread_ptr> ts;
        int num_threads = 35; // 线程数量
        for (size_t i = 0; i < num_threads; i++) { 
            ts.push_back(websocketpp::lib::make_shared<websocketpp::lib::thread>(&server::run, &server_));
        }

        server_.run(); // 总计 num_thread + 1 个线程

        for (size_t i = 0; i < num_threads; i++) {
            ts[i]->join();
        }
    }

    // accept 到一个新的连接之后
    static void accpet_complete(server *s, websocketpp::connection_hdl hdl)
    {
        // 使程序休眠5秒钟
        // std::this_thread::sleep_for(std::chrono::seconds(5));
        
        // 在新线程中处理新连接的回调函数
        // std::thread server_thread([=]() {
            // static int n = 0;
            std::cout << "accpet_complete thread    " << std::this_thread::get_id() << std::endl;
            // 新连接的处理逻辑
            std::cout << "New connection opened!";
            server::connection_ptr con = s->get_con_from_hdl(hdl);
            std::string client_ip = con->get_remote_endpoint(); // 获取ip
            std::cout << " from ------ " << client_ip << std::endl;

            // 将 websocketpp::connection_hdl 转换为字符串
            std::ostringstream oss;
            oss << hdl.lock().get();
            std::string hdl_str = oss.str();
            std::cout << "hdl show by string:   " << hdl_str << std::endl;


            std::cout << std::endl;

            
            // 在这里添加你的其他逻辑
            // std::this_thread::sleep_for(std::chrono::milliseconds(10000));

        // });
        // server_thread.detach(); // 在新线程上运行，分离线程以避免资源泄漏
    }

    // 收到新的数据后（可能是文本 or 二进制数据）
    static void recv_message(server *s, connection_hdl hdl, message_ptr msg)
    {
        // 连接对象 websocketpp::connection_hdl hdl 的地址、连接关闭
        // std::cout << "websocketpp_server::收到数据 " << std::endl;
        // std::cout << "websocketpp_server::recv_message thread   " << std::this_thread::get_id() << std::endl;
        
        op_dis_.processing_data(s,hdl,msg, thread_sever_); // 交给业务分发器处理数据

        
    }


    void on_connection_closed(connection_hdl hdl);


    // ###### 从其它下层模块发来的短小消息 ######
    // 处理 ping 消息(可能是本地客户端的刷新队列信号)
    bool on_ping(connection_hdl hdl, std::string payload);

};

// 构造函数
websocketpp_server::websocketpp_server(/* args */)
{
    // 启用地址复用
    server_.set_reuse_addr(true);


    // 设置日志策略，清除访问通道的所有日志，将错误日志设置为无
    server_.clear_access_channels(websocketpp::log::alevel::all);
    server_.set_error_channels(websocketpp::log::elevel::none);

    // Register handler
    // std::bind()生成一个新的函数对象中，第一个“服务器对象”已经绑定(确定)
    // 后两个参数则在(显示)调用 function 时再给出，其三个参数
    server_.set_open_handler(bind(&accpet_complete, &server_,::_1)); // 建立一个新连接后
    server_.set_message_handler(bind(&recv_message, &server_, ::_1, ::_2)); // 收到数据信息后
    server_.set_ping_handler(bind(&websocketpp_server::on_ping, this, ::_1, ::_2));
    server_.set_close_handler(bind(&websocketpp_server::on_connection_closed, this, ::_1));

}

// 析构函数
websocketpp_server::~websocketpp_server()
{
    
    server_.stop();
    // io_service_thread_->join();
}

// op_dis_ 是静态成员，所以这里要声明一下
op_distributor websocketpp_server::op_dis_;
std::thread* websocketpp_server::thread_sever_;


// ###### 从其它下层模块发来的短小消息 ######
// 有一些短小的数据消息，也会从这里发送给qml客户端
// 处理 ping 消息(可能是本地客户端的刷新队列信号)
bool websocketpp_server::on_ping(connection_hdl hdl, std::string payload)
{
    if(payload == "flush_send_queue")
    {
        SendTask t = SendTaskQueue::getInstance()->front_pop();
        
        std::cout << "本地客户端来的ping准备发送消息给客户端" << std::endl;
        std::cout << "hdl       " << t.hdl_.lock().get() << std::endl;
        std::cout << "thread    " << std::this_thread::get_id() << std::endl;
        std::cout << t.text_;
        
        server_.send(t.hdl_, t.text_, websocketpp::frame::opcode::TEXT);

    }
    else if(payload == "heartbeat")
    {
        std::cout << std::endl;
        std::cout << "heartbeat" << std::endl;
        std::cout << "hdl       " << hdl.lock().get() << std::endl;
        std::cout << std::endl;
    }
    return true;
}


void websocketpp_server::on_connection_closed(connection_hdl hdl)
{
    std::cout << "关闭hdl: " << hdl.lock().get()  << " " << get_time() << std::endl;
    if(UserMgt::is_user_online(UserMgt::nickname_of_id(UserMgt::id_of_hdl(hdl))))
        UserMgt::user_logout(UserMgt::id_of_hdl(hdl));
}

